#ifndef _MATHEMATICS_DEFINE_H_
#define _MATHEMATICS_DEFINE_H_

#include "./../../basic/basic_util.h"

namespace Mathematics {
	using namespace Text;

	/*! pi value. */
	const double pi = 3.1415926535;
	/*! neperian. e. */
	const double nep = 2.718281828;
	
	//! Maximum.
	/*! 
		Maximum of two values
		
		\param a first value
		\param b second value
		\return maximum value
		
		\code
		cout << Max<double>(1,2) << endl;	// prints 2.0
		cout << Max(5,2) << endl;				// prints 5
		\endcode
	*/
	template <class T>
		inline T Max(const T &a, const T &b){
			return (a > b ? a : b );
		};
	
	//! Mininimum.
	/*! 
		Minimum of two values
		
		\param a first value
		\param b second value
		\return minimum value
		
		\code
		cout << Min<double>(1,2) << endl;	// prints 1.0
		cout << Min(5,2) << endl;				// prints 2
		\endcode
	*/
	template <class T>
		inline T Min(const T &a, const T &b){
			return (a <= b ? a : b );
		};
	
	//! Signal.
	/*! 
		Signal of a value
		
		\param a value
		\return 1 if positive, -1 if negative, 0 if neither
		
		\code
		cout << Signal(-2.35) << endl	// prints -1
		\endcode
	*/
	template <class T>
		inline T Signal(const T &a){
			return (a > 0 ? 1 : ( a < 0 ? -1 : 0 ) );
		};
	
	//! Module.
	/*! 
		Euclidian module of a value
		
		\param a value
		\return -a if negative, else a
		
		\code
		cout << Mod(3.5) << endl;	// prints 3.5
		cout << Mod(-3.5) << endl;	// prints 3.5
		\endcode
	*/
	template <class T>
		inline T Mod(const T &a){
			return (a < 0 ? a*-1 : a);
		};
	
	//! Absolute.
	/*! 
		Alias - Mod
		
		\param a value
		\return -a if negative, else a
		
		\sa inline T Mod(const T &a);
	*/
	template <class T>
		inline T Abs(const T &a){
			return Mod(a);
		};
	
	//! Round.
	/*! 
		The round value.
		
		\param a value
		\return the closest integer to the given value
		
		\code
		cout << Round(3.1) << endl;	// prints 3
		cout << Round(3.75) << endl;	// prints 4
		cout << Round(3.5) << endl;	// prints 4. 0.5 gives higher value.
		\endcode
	*/
	inline int Round(const double &a) {
		return Mod(a - ((int)a)) < 0.5 ? (int)a : (int)(a+Signal(a));
	};
	
	//! Double value after the period.
	/*! 
		The fractionary value.
		
		\param a value
		\return the value after the period
		
		\code
		cout << Fract(3.1) << endl;		// prints 0.1
		cout << Fract(3.75) << endl;		// prints 0.75
		cout << Fract(-3.25) << endl;		// prints -0.25
		\endcode
	*/
	inline double Fract(const double &a) {
		return (a - ((int)a));
	};

	//! Lower.
	/*! 
		The lower closest value.
		
		\param a value
		\return the closest integer lower than the given value
		
		\code
		cout << Low(3.1) << endl;	// prints 3
		cout << Low(3.75) << endl;	// prints 3
		cout << Low(-3.1) << endl;	// prints -4
		\endcode
	*/
	inline int Low(const double &a) {
		return  (int)( a - Fract(a) ) + ( a < 0 ? -1 : 0 );
	};
	
	//! Upper.
	/*! 
		The upper closest value.
		
		\param a value
		\return the closest integer higher than the given value
		
		\code
		cout << Upp(3.1) << endl;	// prints 4
		cout << Upp(3.75) << endl;	// prints 4
		cout << Upp(-3.9) << endl;	// prints -3
		\endcode
	*/
	inline int Upp(const double &a) {
		return Low(a)+1;
	};
	
	//! Near (nearest to zero).
	/*! 
		The absolutelly lower closest value.
		
		\param a value
		\return the closest integer with abolute value lower than the given value's module
		
		\code
		cout << Near(3.1) << endl;	// prints 3
		cout << Near(3.75) << endl;	// prints 3
		cout << Near(-3.1) << endl;	// prints -3
		\endcode
	*/
	inline int Near(const double &a) {
		return  (int)( a - Fract(a) );
	};
	
	//! Far (farest to zero).
	/*! 
		The absolutelly higher closest value.
		
		\param a value
		\return the closest integer with abolute value higher than the given value's module
		
		\code
		cout << Far(3.1) << endl;	// prints 4
		cout << Far(3.75) << endl;	// prints 4
		cout << Far(-3.1) << endl;	// prints -4
		\endcode
	*/
	inline int Far(const double &a) {
		return  Near(a) + Signal((int)a);
	};
	
#ifdef USING_STL_CONTAINERS
	/*! container for fatorial values, so it becomes more eficient on each use. */
	extern vector<uint> fat_list;
	/*! container for fibonacci values, so it becomes more eficient on each use. */
	extern vector<uint> fib_list;
#endif

	//! Fatorial
	/*!
		The fatorial of the given value.
		
		\param param value to calculate fatorial
		\return the fatorial
		
		\code
		cout << Fatorial(0) << endl;		// prints 1
		cout << Fatorial(1) << endl;		// prints 1
		cout << Fatorial(2) << endl;		// prints 2
		cout << Fatorial(5) << endl;		// prints 120
		\endcode
	*/
	uint Fat( const usint &param );

	//! Fibonacci
	/*!
		The fibonacci of the given value.
		With each use the parameter's and the lower values' fibonacci are stored and the call
		becomes more eficient.
		
		\param param value to calculate fibonacci value
		\return the fibonacci
		
		\code
		cout << Fibonacci(0) << endl;		// prints 1
		cout << Fibonacci(1) << endl;		// prints 1
		cout << Fibonacci(2) << endl;		// prints 2
		cout << Fibonacci(5) << endl;		// prints 8
		\endcode
	*/
	uint Fib( const usint &param );

	//! function for testing math default definitions
	void MathTest();
	
};

#endif //_MATHEMATICS_DEFINE_H_
